import java.lang.NumberFormatException

/**
 * CRC16 校验工具对象
 *
 * 实现了基于查表法的 CRC16 校验算法。
 * 该实现使用了你提供的 C 语言源代码中的 _CRCHi (216元素) 和 _CRCLo (256元素) 查找表。
 * **警告: _CRCHi 表是不完整的 (只有 216 个元素)，这可能导致在某些输入数据下出现 ArrayIndexOutOfBoundsException。**
 * **如果你需要一个健壮的 CRC 实现，强烈建议使用完整的 256 元素的标准 Modbus CRC16 表。**
 */
object CRC16Util {

    // IMPORTANT: These tables are directly copied from your provided C source code.
    // Note that CRC_HI_TABLE has only 216 elements, while CRC_LO_TABLE has 256.
    // This discrepancy is the root cause of the ArrayIndexOutOfBoundsException when index >= 216.
    // For a standard CRC16 table lookup, both tables MUST be 256 elements long.
    // Using these incomplete tables might lead to crashes with certain input data.

    private val CRC_HI_TABLE = intArrayOf(
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
        0x00, 0xC1, 0x81, 0x40
    ) // Length: 216 elements

    private val CRC_LO_TABLE = intArrayOf(
        0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
        0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
        0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
        0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
        0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
        0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
        0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
        0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
        0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
        0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
        0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
        0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
        0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
        0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
        0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
        0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
        0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
        0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
        0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
        0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
        0x41, 0x81, 0x80, 0x40
    ) // Length: 256 elements

    /**
     * 将十六进制字符串转换为字节数组。
     * @param hex 待转换的十六进制字符串（例如 "010300000002"）。
     * @return 转换后的字节数组。
     * @throws IllegalArgumentException 如果十六进制字符串长度为奇数或包含无效字符。
     */
    private fun hexStringToByteArray(hex: String): ByteArray {
        val cleanHex = hex.replace("\\s".toRegex(), "") // 移除所有空白字符
        require(cleanHex.length % 2 == 0) { "Hex string must have an even number of characters" }

        return try {
            ByteArray(cleanHex.length / 2) { i ->
                val index = i * 2
                Integer.parseInt(cleanHex.substring(index, index + 2), 16).toByte()
            }
        } catch (e: NumberFormatException) {
            throw IllegalArgumentException("Invalid hex character in string: $hex", e)
        }
    }

    /**
     * 计算给定字节数组的 CRC16 校验码。
     *
     * @param data 要计算的数据字节数组。
     * @return 计算得到的 16 位 CRC 校验码 (Int 类型)。
     */
    fun calculateCrc16Bytes(data: ByteArray): Int {
        var crcHigh = 0xFF // 对应C语言的 CRCHi，初始值 0xFF
        var crcLo = 0xFF   // 对应C语言的 CRCLo，初始值 0xFF

        // 迭代处理每一个数据字节
        for (byte in data) {
            // 将 byte 转换为无符号的 Int (0-255)
            val byteAsInt = byte.toInt() and 0xFF

            // 计算查找表的索引
            val index = (crcLo xor byteAsInt)

            // 核心计算逻辑，与 C 代码完全对应
            // CRC_HI_TABLE 只有 216 元素，这里仍有越界风险，取决于 index 的值
            crcLo = crcHigh xor CRC_HI_TABLE[index]
            crcHigh = CRC_LO_TABLE[index]
        }

        // 组合高低字节得到 16 位的 CRC 结果
        return (crcHigh shl 8) or crcLo
    }

    /**
     * 计算给定十六进制字符串指令的 CRC16 校验码。
     *
     * @param hexCommand 不包含CRC校验码的十六进制指令字符串。
     * 例如："010300000002"。
     * @return 计算得到的 16 位 CRC 校验码，以4位大写的十六进制字符串形式返回。
     * 按照协议的小端模式，低字节在前，高字节在后。
     * 例如："0B C4" （如果原始CRC是0xC40B）
     */
    fun calculateCRC16(hexCommand: String): String {
        val data = hexStringToByteArray(hexCommand)
        val crcValue = calculateCrc16Bytes(data)

        // 协议要求小端模式：低字节在前，高字节在后。
        val crcLowByte = crcValue and 0xFF
        val crcHighByte = (crcValue shr 8) and 0xFF

        // 格式化为两位16进制字符串，并拼接成小端模式 (低字节在前，高字节在后)
        return String.format("%02X%02X", crcLowByte, crcHighByte)
    }
}

// 示例用法
fun main() {
    // 传入你报错的字符串
    val commandWithSpaces = "00 64 FF FF 30 14 01 BB B6 D3 AD B9 E2 C1 D9 2C C7 EB C8 EB B3 A1 CD A3 B3 B5"
    val crcWithError = CRC16Util.calculateCRC16(commandWithSpaces)
    println("指令: '$commandWithSpaces', CRC16: $crcWithError")
    // 对于标准 Modbus CRC16，期望输出: A936

    val command1 = "010300000001"
    val crc1 = CRC16Util.calculateCRC16(command1)
    println("指令: '$command1', CRC16: $crc1")
    // 对于标准 Modbus CRC16，期望输出: BBC5

    val command2 = "12345678"
    val crc2 = CRC16Util.calculateCRC16(command2)
    println("指令: '$command2', CRC16: $crc2")

    val command3 = "" // 空数据
    val crc3 = CRC16Util.calculateCRC16(command3)
    println("指令: '$command3', CRC16: $crc3")
    // 期望输出: FFFF

    // 测试无效输入
    try {
        val command4 = "123" // 长度为奇数
        val crc4 = CRC16Util.calculateCRC16(command4)
        println("指令: '$command4', CRC16: $crc4")
    } catch (e: IllegalArgumentException) {
        println("捕获到异常：${e.message}")
    }

    try {
        val command5 = "123G" // 包含非法字符
        val crc5 = CRC16Util.calculateCRC16(command5)
        println("指令: '$command5', CRC16: $crc5")
    } catch (e: IllegalArgumentException) {
        println("捕获到异常：${e.message}")
    }
}